package me.eg.forth;

import java.util.*;

/**
 * 355. 设计推特
 * <p>
 * 设计一个简化版的推特(Twitter)，可以让用户实现发送推文，关注/取消关注其他用户，能够看见关注人（包括自己）的最近 10 条推文。
 * <p>
 * 实现 Twitter 类：
 * <p>
 * Twitter() 初始化简易版推特对象
 * void postTweet(int userId, int tweetId) 根据给定的 tweetId 和 userId 创建一条新推文。每次调用次函数都会使用一个不同的 tweetId 。
 * List<Integer> getNewsFeed(int userId) 检索当前用户新闻推送中最近  10 条推文的 ID 。新闻推送中的每一项都必须是由用户关注的人或者是用户自己发布的推文。推文必须 按照时间顺序由最近到最远排序 。
 * void follow(int followerId, int followeeId) ID 为 followerId 的用户开始关注 ID 为 followeeId 的用户。
 * void unfollow(int followerId, int followeeId) ID 为 followerId 的用户不再关注 ID 为 followeeId 的用户。
 * <p>
 * 链接：https://leetcode-cn.com/problems/design-twitter
 */
public class Twitter {
    Map<Integer, Set<Integer>> followMap; // 关注列表
    Map<Integer, TweetMsg> tweetList; // 推特列表
    private int curMsgId;
    private int recentMax;

    public Twitter() {
        followMap = new HashMap<>();
        tweetList = new HashMap<>();
        curMsgId = 0;
        recentMax = 10;
    }

    public void postTweet(int userId, int tweetId) {
        TweetMsg newTweet = new TweetMsg(++curMsgId, tweetId);
        TweetMsg oldtweets = null;
        if (tweetList.containsKey(userId)) oldtweets = tweetList.get(userId);
        newTweet.next = oldtweets;
        tweetList.put(userId, newTweet);
    }

    public List<Integer> getNewsFeed(int userId) {
        PriorityQueue<TweetMsg> heap = new PriorityQueue<>();
        Set<Integer> follows = this.getFollowee(userId);
        for (Integer followeeId : follows) {
            if (tweetList.containsKey(followeeId)) heap.offer(tweetList.get(followeeId));
        }

        List<Integer> ans = new LinkedList<>();
        while (ans.size() < recentMax && !heap.isEmpty()) {
            TweetMsg msg = heap.poll();
            ans.add(msg.tweetId);
            if (msg.next != null) heap.offer(msg.next);
        }
        return ans;
    }

    public void follow(int followerId, int followeeId) {
        Set<Integer> follows = this.getFollowee(followerId);
        if (!follows.contains(followeeId)) {
            follows.add(followeeId);
            followMap.put(followerId, follows);
        }
    }

    public void unfollow(int followerId, int followeeId) {
        Set<Integer> follows = followMap.get(followerId);
        if (follows != null && follows.contains(followeeId)) {
            follows.remove(followeeId);
            followMap.put(followerId, follows);
        }
    }

    private Set<Integer> getFollowee(int followerId) {
        Set<Integer> follows = followMap.getOrDefault(followerId, new HashSet<>());
        if (follows.isEmpty()) follows.add(followerId); // 自己是自己的关注者
        return follows;
    }

    class TweetMsg implements Comparable {
        public int msgId;
        public int tweetId;
        public TweetMsg next;

        public TweetMsg(int msgId, int tweetId) {
            this.msgId = msgId;
            this.tweetId = tweetId;
        }

        @Override
        public int compareTo(Object o) {
            TweetMsg other = (TweetMsg) o;
            return other.msgId - this.msgId;
        }
    }
}

